package mysqldao

import (
	"ahutoj/web/dao"
	"ahutoj/web/utils"
	"context"
	"errors"
	"fmt"
	"strings"

	"gorm.io/gorm"
)

func SelectUserByUID(ctx context.Context, user *dao.User) error {
	db := GetDB(ctx)
	// select * from User where UID = ''
	err := db.Where("UID=?", user.UID).First(user).Error
	return err
}

func SelectUserByEmail(ctx context.Context, user *dao.User) error {
	db := GetDB(ctx)
	// select * from User where UID = ''
	err := db.Where("Email=?", user.Email).First(user).Error
	return err
}

func SelectUserCountByUID(ctx context.Context, UID string) (count int64, err error) {
	db := GetDB(ctx)
	err = db.Table(dao.User{}.TableName()).Where("UID=?", UID).Count(&count).Error
	return count, err
}

func SelectUserCountByEmail(ctx context.Context, Email string) (count int64, err error) {
	db := GetDB(ctx)
	err = db.Table(dao.User{}.TableName()).Where("Email=?", Email).Count(&count).Error
	return count, err
}
func SelectUserCount(ctx context.Context) (count int64, err error) {
	db := GetDB(ctx)
	err = db.Table(dao.User{}.TableName()).Count(&count).Error
	return count, err
}

func InsertUserTable(ctx context.Context, user dao.User) error {
	db := GetDB(ctx)
	err := db.Create(&user).Error
	return err
}

func UpdateUserByUID(ctx context.Context, user *dao.User) error {
	db := GetDB(ctx)
	err := db.Table(dao.User{}.TableName()).Where("UID=?", user.UID).Updates(&user).Error
	return err
}
func UpdateUserByEmail(ctx context.Context, user *dao.User) error {
	db := GetDB(ctx)
	err := db.Table(dao.User{}.TableName()).Where("Email=?", user.Email).Updates(&user).Error
	return err
}
func UpdateEmailByUID(ctx context.Context, UID string, email string) error {
	db := GetDB(ctx)
	err := db.Table(dao.User{}.TableName()).Where("UID=?", UID).Update("Email", email).Error
	return err
}
func SelectEmail(ctx context.Context, email string) (int64, error) {
	db := GetDB(ctx)
	var count int64
	err := db.Table(dao.User{}.TableName()).Where("Email=?", email).Count(&count).Error
	return count, err
}
func SelectUserEmail(ctx context.Context, uid string, email string) error {
	db := GetDB(ctx)
	err := db.Table(dao.User{}.TableName()).Where("Email=? and UID=?", email, uid).First(&dao.User{}).Error
	return err
}
func SelectUserList(ctx context.Context, token string, offset, limit int) ([]dao.User, error) {
    db := GetDB(ctx)
    users := make([]dao.User, 0)
    query := db.Table(dao.User{}.TableName())
    if token != "" {
        query = query.Where("UID LIKE ? OR UserName LIKE ?", "%"+token+"%", "%"+token+"%")
    }
    err := query.Offset(offset).Limit(limit).Find(&users).Error
    return users, err
}
func SelectUserSolutionList(ctx context.Context, UID string, Page int, Limit int) (*[]dao.Solution, error) {
	db := GetDB(ctx)
	solutions := make([]dao.Solution, 0)
	err := db.Table(dao.Solution{}.TableName()).Where("UID=? AND IsDelete=0", UID).Offset((Page - 1) * Limit).Limit(Limit).Find(&solutions).Error
	return &solutions, err
}

func IncUserSubmited(ctx context.Context, UID string) error {
	db := GetDB(ctx)
	user := dao.User{}
	return db.Table(user.TableName()).Where("UID=?", UID).UpdateColumn("Submited", gorm.Expr("Submited+1")).Error
}

func IncUserSolved(ctx context.Context, UID string) error {
	db := GetDB(ctx)
	user := dao.User{}
	fmt.Println(UID)
	return db.Table(user.TableName()).Where("UID=?", UID).UpdateColumn("Solved", gorm.Expr("Solved+1")).Error
}

func SelectUserByQQ(ctx context.Context, QQ string) (*dao.User, error) {
	db := GetDB(ctx)
	user := dao.User{}
	err := db.Table(user.TableName()).Where("QQ=?", QQ).First(&user).Error
	return &user, err
}

func UpdateUserQQ(ctx context.Context, user *dao.User) error {
	db := GetDB(ctx)
	err := db.Table(dao.User{}.TableName()).Where("UID=?", user.UID).Update("QQ", user.QQ).Error
	return err
}

func AddGroup(ctx context.Context, group dao.Group) error {
	db := GetDB(ctx)
	err := db.Table(dao.Group{}.TableName()).Create(&group).Error
	return err
}
func FindGroup(ctx context.Context, group *dao.Group) error {
	db := GetDB(ctx)
	err := db.Table(dao.Group{}.TableName()).Where(group).Last(group).Error
	return err
}

func DeleteGroup(ctx context.Context, GID int64) error {
	db := GetDB(ctx)
	return db.Delete(&dao.Group{}, "GID = ?", GID).Error
}

func EditGroup(ctx context.Context, group *dao.Group) error {
	db := GetDB(ctx)
	err := db.Table(dao.Group{}.TableName()).Where("GID=?", group.GID).Updates(group).Error
	return err
}

func UpdateGroupUserRole(ctx context.Context, groupUser *dao.GroupUser) error {
	db := GetDB(ctx)
	err := db.Table(dao.GroupUser{}.TableName()).Where("GID=? AND UID=?", groupUser.GID, groupUser.UID).Updates(groupUser).Error
	return err
}

func GetGroupUser(ctx context.Context, GID int64, UID string) (*dao.GroupUser, error) {
	db := GetDB(ctx)
	groupUser := dao.GroupUser{}
	err := db.Table(dao.GroupUser{}.TableName()).Where("UID=? AND GID=?", UID, GID).First(&groupUser).Error
	return &groupUser, err
}
func GetGroupUserList(ctx context.Context, GID int64) ([]dao.GroupUser, error) {
	db := GetDB(ctx)
	groupUser := new([]dao.GroupUser)
	err := db.Table(dao.GroupUser{}.TableName()).Where("GID=?", GID).Find(groupUser).Error
	return *groupUser, err
}

func GetGroupList(ctx context.Context, UID string, offset, limit int) (*[]dao.Group, error) {
	db := GetDB(ctx)
	var groups []dao.Group
	err := db.Table(dao.Group{}.TableName()).Where("UID=?", UID).Offset(offset).Limit(limit).Find(&groups).Error
	return &groups, err
}

func GetGroup(ctx context.Context, GID int64) (*dao.Group, error) {
	db := GetDB(ctx)
	var group dao.Group
	err := db.Table(dao.Group{}.TableName()).Where("GID=?", GID).First(&group).Error
	return &group, err
}

func GetGroupByInviteCode(ctx context.Context, inviteCode string) (*dao.Group, error) {
	db := GetDB(ctx)
	var group dao.Group
	err := db.Table(dao.Group{}.TableName()).Where("InviteCode=?", inviteCode).First(&group).Error
	return &group, err
}

func AddUserToGroup(ctx context.Context, groupUser dao.GroupUser) error {
	db := GetDB(ctx)
	err := db.Table(dao.GroupUser{}.TableName()).Create(&groupUser).Error
	return err
}

func DeleteUserFromGroup(ctx context.Context, GID int64, UID string) error {
	db := GetDB(ctx)
	err := db.Table(dao.GroupUser{}.TableName()).Where("GID=? AND UID=?", GID, UID).Delete(&dao.GroupUser{}).Error
	return err
}

func GetGroupSubmit(ctx context.Context, groupUserList *[]dao.GroupUser, group *dao.Group) (*[]dao.Submit, error) {
	logger := utils.GetLogInstance()
	db := GetDB(ctx)
	var uids []string
	for _, user := range *groupUserList {
		uids = append(uids, user.UID)
	}
	tasks := strings.Split(group.GroupTask, ";")
	var cTasks, pTasks, lTasks []string
	for _, task := range tasks {
		if len(task) <= 0 {
			return nil, errors.New("need task "+fmt.Sprintf("tasks:%v",tasks))
		}
		switch task[0] {
		case 'C':
			cTasks = append(cTasks, task[1:])
		case 'L':
			lTasks = append(lTasks, task[1:])
		case 'P':
			pTasks = append(pTasks, task[1:])
		default:
			pTasks = append(pTasks, task)
		}
	}
	logger.Debugf("%v", utils.Sdump(cTasks, lTasks, pTasks))
	query := db.Table(dao.Submit{}.TableName()).Where("UID IN (?)", uids).Where("ResultACM = ?", "AC")
	if len(pTasks) > 0 || len(lTasks) > 0 || len(cTasks) > 0 {
		orConditions := []string{}
		args := []interface{}{}
		if len(pTasks) > 0 {
			orConditions = append(orConditions, "PID IN (?)")
			args = append(args, pTasks)
		}
		if len(lTasks) > 0 {
			orConditions = append(orConditions, "LID IN (?)")
			args = append(args, lTasks)
		}
		if len(cTasks) > 0 {
			orConditions = append(orConditions, "CID IN (?)")
			args = append(args, cTasks)
		}
		query = query.Where(strings.Join(orConditions, " OR "), args...)
	}

	var submits []dao.Submit
	err := query.Find(&submits).Error
	if err != nil {
		return nil, err
	}

	return &submits, nil
}
